﻿# -*- coding:utf-8 -*-
#
# views.py
# 
# Files storage system
#
from django.conf import settings
from django.shortcuts import render_to_response
from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.http import HttpResponseServerError
from django.core.urlresolvers import reverse
from django.core.files.uploadhandler import FileUploadHandler
from django.template import RequestContext, Context
from django.utils import simplejson
from django.contrib.auth.decorators import login_required
from django.contrib.sessions.backends.db import SessionStore
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.contrib.auth.decorators import permission_required

#from django.core.cache import cache
#from django.db.models.loading import get_model
#from django.http import Http404
#from django.contrib.auth.models import User
#from django.http import HttpResponseForbidden

from homesite.files.models import File, Category
from homesite.files.forms import FileForm, FileEditForm, CategoryCreateForm, CategoryEditForm

class UploadProgressHandler(FileUploadHandler):

    def __init__(self, request, progress_id=None):
        super(UploadProgressHandler, self).__init__(request)
        self.progress_id = progress_id
        self.request = request
        self.cache_key = None

    def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
        self.content_length = content_length
        if self.progress_id:
            
            self.cache_key = "%s_%s" % (META['REMOTE_ADDR'], self.progress_id)
            try:
                s = SessionStore(session_key=self.request.session.session_key)
            except:
                return None
            
            #if self.request.POST['title'] == '':
            #    s[self.cache_key] = {
            #        'length': self.content_length,
            #        'uploaded' : 0,
            #        'error' : u'Title none',
            #        'complete' : True
            #    }
            
            #else:
            s[self.cache_key] = {
                'length': self.content_length,
                'uploaded' : 0,
                'error' : u'',
                'complete' : False
            }
            
            s.save()
        return None

    def new_file(self, field_name, file_name, content_type, content_length, charset=None):
        pass

    def receive_data_chunk(self, raw_data, start):
        if self.cache_key:
            try:
                s = SessionStore(session_key=self.request.session.session_key)
            except:
                return raw_data
            data = s[self.cache_key]
            if data:
                data['uploaded'] += self.chunk_size
                s[self.cache_key] = data
                s.save()
        return raw_data

    def file_complete(self, file_size):
        pass

    def upload_complete(self):
        if self.cache_key:
            s = SessionStore(session_key=self.request.session.session_key)
            data = s[self.cache_key]
            if data:
                data['complete'] = True
                s[self.cache_key] = data
                s.save()


@login_required 
def uploader(request, category_id):
    category = get_object_or_404(Category, id=category_id)
    error = None
    progress_id = None
    if 'X-Progress-ID' in request.GET:
        progress_id = request.GET['X-Progress-ID']
    elif 'X-Progress-ID' in request.META:
        progress_id = request.META['X-Progress-ID']
    cache_key = "%s_%s" % (request.META['REMOTE_ADDR'], progress_id)
    
    request.upload_handlers.insert(0, UploadProgressHandler(request, progress_id))
    if request.method == 'POST':
        upl_form = FileForm( category, request.user, request.FILES['name'], '', request.POST, request.FILES)
        if upl_form.is_valid():
            if progress_id:
                status_data = request.session.get(cache_key, None)
            upl_form.save()
            return HttpResponse('Ok')
        request.session[cache_key] = {
                'length': 1,
                'uploaded' : 0,
                'error' : u'Обязательные поля не заполнены',
                'complete' : True
            }
        return HttpResponse('not Ok') 
 
 
 
def uploader_progress(request):
    """
    Return JSON object with information about the progress of an upload.
    """
    progress_id = ''
    if 'X-Progress-ID' in request.GET:
        progress_id = request.GET['X-Progress-ID']
    elif 'X-Progress-ID' in request.META:
        progress_id = request.META['X-Progress-ID']
    if progress_id:
        cache_key = "%s_%s" % (request.META['REMOTE_ADDR'], progress_id)
        data = request.session.get(cache_key, None)
        if data:
            if data["complete"]: 
                del request.session[cache_key]
        return HttpResponse(simplejson.dumps(data))
    else:
        return HttpResponseServerError('Server Error: You must provide X-Progress-ID header or query param.')


def context_processor(request):
    "A context processor."
    return {
    }


@login_required
def index(request):
    files_list = File.objects.filter(category=None)
    if len(files_list) != 0:
        paginator = Paginator(files_list, 8) # Show 8 files per page
        try:
            page = int(request.GET.get('page', '1'))
        except ValueError:
            page = 1
        try:
            files = paginator.page(page)
        except (EmptyPage, InvalidPage):
            files = paginator.page(paginator.num_pages)
    else:
        files = None   
    categorys = get_category_list(None)
    context = Context({
      'files': files,
      'categorys':categorys,
      'catalog_halflength':(len(categorys) + 1) / 2,
    })
    return render_to_response('files/index.html', context, context_instance=RequestContext(request, processors=[context_processor]))


@login_required
def category_list(request, category_id):
    files_list = File.objects.filter(category=category_id)
    categorys = get_category_list(category_id)
    if len(files_list) != 0:
        paginator = Paginator(files_list, 8) # Show 8 files per page
        try:
            page = int(request.GET.get('page', '1'))
        except ValueError:
            page = 1
        try:
            files = paginator.page(page)
        except (EmptyPage, InvalidPage):
            files = paginator.page(paginator.num_pages)
    else:
        files = None
    category_path = get_category_path(category_id)
    category = category_path[-1]
    context = Context({
        'files': files,
        'categorys':categorys,
        'category_path':category_path,    
        'catalog_halflength':(len(categorys) + 1) / 2,
        'category_id':category_id, 
        'category':category,
    })
    return render_to_response('files/category.html', context, context_instance=RequestContext(request, processors=[context_processor]))    
    

@login_required
def download(request, file_id):
    dl_file = get_object_or_404(File, id=file_id)
    response = HttpResponse(dl_file.name, mimetype='application/octet-stream')
    response['Content-Length'] = dl_file.name.size 
    response['Content-Disposition'] = 'attachment; filename=%s' % dl_file.name_real.encode('cp1251','ignore')
    i = dl_file.download_cnt
    dl_file.download_cnt = i + 1
    dl_file.save()
    return response


@login_required
@permission_required('files.add_file')
def file_upload(request, category_id):
    form = FileForm(category_id, request.user, '', '')
    context = Context({
      'form': form,
      'category_id':category_id, 
      'category_path':get_category_path(category_id), 
    })
    return render_to_response('files/fileupload.html', context, context_instance=RequestContext(request, processors=[context_processor]))



@login_required
@permission_required('files.delete_file')
def file_delete(request, file_id):
    file = get_object_or_404(File, id=file_id)
    category_id = file.category.id
    file.name.delete()
    file.delete()
    request.user.message_set.create(message="Файл был успешно удален.")
    return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[category_id]))
    
    
@login_required
@permission_required('files.change_file')
def file_edit(request, file_id):   
    fileitem = get_object_or_404(File, id=file_id)
    if request.method == 'POST':
        form = FileEditForm(request.POST, instance=fileitem)
        if form.is_valid():
            fileitem.title = form.cleaned_data['title']
            fileitem.description = form.cleaned_data['description']
            fileitem.category = form.cleaned_data['category']
            fileitem.save()
            request.user.message_set.create(message="Свойства файла успешно сохранены.")
            return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[fileitem.category.id]))
    else:
        form = FileEditForm(instance=fileitem)
    context = Context({
      'form': form,
      'fileitem':fileitem,
      'category_path':get_category_path(fileitem.category_id),
    })
    return render_to_response('files/fileedit.html', context, context_instance=RequestContext(request, processors=[context_processor]))



@login_required
@permission_required('files.add_category')
def category_root_create(request):
    if request.method == 'POST':
        form = CategoryCreateForm(None, request.POST)
        if form.is_valid():
            form.save()
            request.user.message_set.create(message="Категория успешно создана.")
            return HttpResponseRedirect(reverse('homesite.files.views.index',args=[]))
    else:
        form = CategoryCreateForm(None)
    context = Context({
      'form': form,
    })
    return render_to_response('files/category_create.html', context, context_instance=RequestContext(request, processors=[context_processor]))
    
    

@login_required
@permission_required('files.add_category')
def category_create(request, category_id):
    categoryitem = get_object_or_404(Category, id=category_id)
    if request.method == 'POST':
        form = CategoryCreateForm(categoryitem, request.POST)
        if form.is_valid():
            form.save()
            request.user.message_set.create(message="Категория успешно создана.")
            return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[category_id]))
    else:
        form = CategoryCreateForm(categoryitem)
    context = Context({
      'form': form,
      'category':categoryitem,
      'category_path':get_category_path(category_id),    
    })
    return render_to_response('files/category_create.html', context, context_instance=RequestContext(request, processors=[context_processor]))



@login_required
@permission_required('files.change_category')
def category_edit(request, category_id):
    categoryitem = get_object_or_404(Category, id=category_id)
    if request.method == 'POST':
        form = CategoryEditForm(request.POST, instance=categoryitem)
        if form.is_valid():
            form.save()
            request.user.message_set.create(message="Категория успешно изменена.")
            return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[category_id]))
    else:
        form = CategoryEditForm(instance=categoryitem)
    context = Context({
      'form': form,
      'category':categoryitem,
      'category_path':get_category_path(category_id),    
    })
    return render_to_response('files/category_edit.html', context, context_instance=RequestContext(request, processors=[context_processor]))



@login_required    
@permission_required('files.delete_category')
def category_delete(request, category_id):
    categoryitem = get_object_or_404(Category, id=category_id)
    childs = Category.objects.filter(parent=category_id).count()
    if childs != 0:
        request.user.message_set.create(message="Удаление невозможно! Есть подкатегории.")
        return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[category_id]))
    files = File.objects.filter(category=category_id).count()  
    if files != 0:
        request.user.message_set.create(message="Удаление невозможно! Категория содержит файлы.")
        return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[category_id]))
    if categoryitem.parent != None:
        category_id = categoryitem.parent.id
    else:
        category_id = 0
    categoryitem.delete()
    request.user.message_set.create(message="Категория успешно удалена.")
    if category_id != 0:
        return HttpResponseRedirect(reverse('homesite.files.views.category_list',args=[category_id]))
    else: 
        return HttpResponseRedirect(reverse('homesite.files.views.index',args=[]))   


    
def get_category_path(category_id):
    path = []
    category = Category.objects.select_related().get(id=category_id)
    while category != None:
        path.insert(0,category)
        category = category.parent
    return path



def get_category_list(category_id):
    result = []
    category = Category.objects.select_related().filter(parent=category_id)
    for cat_item in category:
        item = {}
        item["id"]=cat_item.id
        item["title"]=cat_item.title
        item["child"]=Category.objects.filter(parent=cat_item.id) 
        result.append(item)
    return result

   
@login_required    
#@permission_required('files.delete_category')
def file_property(request,  file_id):   
    file = get_object_or_404(File, id=file_id)
    category_id = file.category.id
    categoryitem = get_object_or_404(Category, id=category_id)
    
    context = Context({
      'file': file,
      'category':categoryitem,
      'category_path':get_category_path(category_id), 
      'category_id':category_id,
    })   
    return render_to_response('files/file_property.html', context, context_instance=RequestContext(request, processors=[context_processor]))

